<?php

// **************************************************************
// | Name: 星空框架  银联支付模块
// **************************************************************
// | Version: V5.0
// **************************************************************
// | Author: xkyinzhe <zhonghuaxinxing@sina.cn>
// **************************************************************
// | City: 青岛
// **************************************************************
// | Time: 2021-10-22 10:36 
// **************************************************************
declare(strict_types=1);

namespace app\common\controller;

use app\common\common\BaseController;
use app\common\model\Order as OrderModel;
use app\common\model\SubOrder as SubOrderModel;
use app\common\model\GoodsOrder as GoodsOrderModel;
use app\common\model\RefundOrder as RefundOrderModel;
use app\common\services\OrderServices;
use app\common\model\Pay as PayModel;
use app\common\services\UserServices;
use app\common\services\FinanceServices;
use app\common\services\Lock;
use app\common\services\Task;
use think\facade\Cache;
use think\facade\Db;

/**
 * @xk 银联支付
 */
class Unionpay extends BaseController
{
    /**
     * @xk 银联支付
     *
     * @method wechatPay
     * @param  [type]     $order_data                [description]
     * @return [type]     [description]
     * @Time   2021-10-22
     * @City   青岛
     * @Author xkyinzhe   <zhonghuaxinxing@sina.cn>
     */
    public static function wecahtPay($order_data = [], $be_from = 'H5')
    {
        $orderModel = new OrderModel();
        $post_data = [];
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $order_sn = $order_data['order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额
        $pay_order_sn = $orderModel->getCodeNo(config('pay_config.unionpay.msgSrcId') . $order_sn, 30, 1);
        $pay_style = 0;
        if ($be_from == 'H5') {
            $pay_style = 1;
        }
        // $pay_order_sn = config('pay_config.unionpay.msgSrcId').$order_sn;
        $orderModel->where([['order_sn', '=', $order_sn]])
            ->find()
            ->save(['pay_order_sn' => $pay_order_sn, 'pay_style' => $pay_style]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=all&order_sn=' . $order_sn;
        switch ($be_from) {
            case 'H5':
                $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=all&order_sn=' . base64_encode($order_sn).'&user_sn='.base64_encode($order_data['user_sn']);
                $openid = $order_data['wechat_openId'];
                return self::doWechatPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl,"h5");
                break;
            case 'wxapp':
                $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=all&order_sn=' . base64_encode($order_sn).'&user_sn='.base64_encode($order_data['user_sn']);
                $openid = $order_data['wechat_app_openId'];
                return self::doWechatAppPay($pay_order_sn, $need_pay, $openid, $notifyUrl, $returnUrl);
                break;
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
                return self::doAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
        }
    }
    /**
     * @xk 子订单支付
     *
     * @method subOrderPay
     * @param  array       $order_data                [description]
     * @return [type]      [description]
     * @Time   2021-10-23
     * @City   青岛
     * @Author xkyinzhe    <zhonghuaxinxing@sina.cn>
     */
    public static function subOrderPay($order_data = [], $be_from = 'H5')
    {
        $subOrderModel = new SubOrderModel();
        $post_data = [];
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $sub_order_sn = $order_data['sub_order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额

        // $pay_order_sn = $subOrderModel->getCodeNo(config('pay_config.unionpay.msgSrcId').$sub_order_sn, 30, 1);
        $pay_order_sn = config('pay_config.unionpay.msgSrcId') . $sub_order_sn;
        $subOrderModel->where([['sub_order_sn', '=', $sub_order_sn]])->find()->save(['pay_order_sn' => $pay_order_sn]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.subOrderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=sub&order_sn=' . $sub_order_sn;
        switch ($be_from) {
            case 'H5':
                $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=sub&order_sn=' . base64_encode($sub_order_sn).'&user_sn='.base64_encode($order_data['user_sn']);
                return self::doWechatPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl,"h5");
                break;
            case 'wxapp':
                $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=sub&order_sn=' . base64_encode($sub_order_sn).'&user_sn='.base64_encode($order_data['user_sn']);
                $openid = $order_data['wechat_app_openId'];
                return self::doWechatAppPay($pay_order_sn, $need_pay, $openid, $notifyUrl, $returnUrl);
                break;
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                return self::doAppPay($pay_order_sn, $need_pay, $notifyUrl, $openid);
                break;
        }
    }
    /**
     * @xk 执行支付宝app支付
     * @method                                      aliPay
     * @param                                       array $order_data  [description]
     * @param                                       string $be_from  [description]
     * @return                                      [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                             <zhonghuaxinxing@sina.cn>
     * @City：                                       青岛
     * @Time：2022-03-08Tfalse11:false14:false11+080
     */
    public static function aliPay($order_data = [], $be_from = 'app')
    {
        $orderModel = new OrderModel();
        $post_data = [];
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $order_sn = $order_data['order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额
        $pay_order_sn = $orderModel->getCodeNo(config('pay_config.unionpay.msgSrcId') . $order_sn, 30, 1);
        // $pay_order_sn = config('pay_config.unionpay.msgSrcId').$order_sn;
        // $pay_order_sn = config('pay_config.unionpay.msgSrcId').$order_sn;
        $orderModel->where([['order_sn', '=', $order_sn]])->find()->save(['pay_order_sn' => $pay_order_sn]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=all&order_sn=' . $order_sn;
        // echo $be_from; die();
        switch ($be_from) {
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
                return self::doAliAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
        }
    }
    /**
     * @xk 支付宝子订单支付
     * @method                                      subOrderAliPay
     * @param                                       array $order_data  [description]
     * @param                                       string $be_from  [description]
     * @return                                      [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                             <zhonghuaxinxing@sina.cn>
     * @City：                                       青岛
     * @Time：2022-03-08Tfalse11:false16:false25+080
     */
    public static function subOrderAliPay($order_data = [], $be_from = 'app')
    {
        $subOrderModel = new SubOrderModel();
        $post_data = [];
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $sub_order_sn = $order_data['sub_order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额
        // $pay_order_sn = $subOrderModel->getCodeNo(config('pay_config.unionpay.msgSrcId').$sub_order_sn, 30, 1);
        $pay_order_sn = config('pay_config.unionpay.msgSrcId') . $sub_order_sn;
        $subOrderModel->where([['sub_order_sn', '=', $sub_order_sn]])->find()->save(['pay_order_sn' => $pay_order_sn]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.subOrderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=sub&order_sn=' . $sub_order_sn;
        switch ($be_from) {
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                return self::doAliAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
        }
    }
    // ***************************
    // | 银联支付
    // *****************************
    /**
     * @xk 执行银联支付
     *
     * @Version: V1.0
     * @Author: xkyinzhe <zhonghuaxinxing@sina.cn>
     * @City: 青岛
     * @Time 2024-01-30
     * @param array $order_data
     * @param string $be_from
     * @return void
     */
    public static function uniPay($order_data = [], $be_from = 'H5')
    {

        $orderModel = new OrderModel();
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $order_sn = $order_data['order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额
        $pay_order_sn = $orderModel->getCodeNo(config('pay_config.unionpay.msgSrcId') . $order_sn, 30, 1);
        $pay_style = 0;
        if ($be_from == 'H5') {
            $pay_style = 1;
        }
        // $pay_order_sn = config('pay_config.unionpay.msgSrcId').$order_sn;
        $orderModel->where([['order_sn', '=', $order_sn]])
            ->find()
            ->save(['pay_order_sn' => $pay_order_sn, 'pay_style' => $pay_style]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=all&order_sn=' . $order_sn;
        switch ($be_from) {
            case 'H5':
                // $openid = $order_data['wechat_openId'];
                $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_ysf_success?act=all&order_sn=' . $order_sn;
                return self::doUniH5Pay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.orderPayBack');
                return self::doUniAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
        }
    }
    /**
     * @xk 执行银联子订单支付
     *
     * @Version: V1.0
     * @Author: xkyinzhe <zhonghuaxinxing@sina.cn>
     * @City: 青岛
     * @Time 2024-01-30
     * @param array $order_data
     * @param string $be_from
     * @return void
     */
    public static function subUniPay($order_data = [], $be_from = 'H5')
    {
        $subOrderModel = new SubOrderModel();
        if (!$order_data) {
            throw new \think\Exception("支付订单错误", 404);
        }
        $sub_order_sn = $order_data['sub_order_sn'];
        $need_pay = $order_data['need_pay'] * 100; // 组合支付金额

        // $pay_order_sn = $subOrderModel->getCodeNo(config('pay_config.unionpay.msgSrcId').$sub_order_sn, 30, 1);
        $pay_order_sn = config('pay_config.unionpay.msgSrcId') . $sub_order_sn;
        $subOrderModel->where([['sub_order_sn', '=', $sub_order_sn]])->find()->save(['pay_order_sn' => $pay_order_sn]);
        $notifyUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/' . config('pay_config.unionpay.subOrderPayBack');
        $returnUrl = 'https://' . $_SERVER['HTTP_HOST'] . '/#/pages/pay_success/pay_success?act=sub&order_sn=' . $sub_order_sn;
        switch ($be_from) {
            case 'H5':
                return self::doUniH5Pay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl);
                break;
            case 'app':
                $openid = $order_data['wechat_app_openId'];
                return self::doUniAppPay($pay_order_sn, $need_pay, $notifyUrl, $openid);
                break;
        }
    }
    /**
     * @xk 组合支付参数等信息
     *
     * @method doWechatPay
     * @param  [type]      $pay_order_sn              [description]
     * @param  [type]      $need_pay                  [description]
     * @param  [type]      $notifyUrl                 [description]
     * @param  [type]      $returnUrl                 [description]
     * @return [type]      [description]
     * @Time   2021-10-23
     * @City   青岛
     * @Author xkyinzhe    <zhonghuaxinxing@sina.cn>
     */
    public static function doWechatPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl,$type="")
    {
        // 前台下单模式
        $app_id = config('pay_config.unionpay.app_id');
        $app_key = config('pay_config.unionpay.app_key');
        $timestamp = date('YmdHis');
        $nonce_str = self::nocestr();
        $post_data = [];
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $cancel_time = (int)config('web_config.cancel_hour') * 3600;
        $post_data['expireTime'] = date('Y-m-d H:i:s', time() + $cancel_time); // 一小时后自动关闭订单 重新发起
        $post_data['merOrderId'] = $pay_order_sn; // 订单支付编号
        $post_data['mid'] = config('pay_config.unionpay.wechat_mid');
        $post_data['tid'] = config('pay_config.unionpay.wechat_tid');
        // if($type!="h5"){
            $post_data['instMid'] = config('pay_config.unionpay.instMid');
        // }else{
            // $post_data['instMid'] = "H5DEFAULT";
            // $post_data['sceneType']="AND_WAP";
            // $post_data['merAppName']="易得悠品";
            // $post_data['merAppId']="https://cs.qdlinquan.com";
        // }
        $post_data['orderDesc'] = '用户使用微信支付商品';
        $post_data['totalAmount'] = strval($need_pay);
        $post_data['notifyUrl'] = $notifyUrl;
        $post_data['returnUrl'] = $returnUrl;
        // var_dump($post_data);die;
        $content = json_encode($post_data);
        $string = $app_id . $timestamp . $nonce_str . hash('sha256', $content);
        $sign = Base64_Encode(hash_hmac('sha256', $string, $app_key, true));
        // if($type!="h5"){
            $url = 'https://api-mop.chinaums.com/v1/netpay/webpay/pay';
        // }else{
            // $url="https://api-mop.chinaums.com/v1/netpay/wxpay/h5-pay";
            // $url="https://test-api-open.chinaums.com/v1/netpay/wxpay/h5-to-minipay";
        // }
        
        $url .= "?authorization=OPEN-FORM-PARAM&appId=" . $app_id . '&timestamp=' . $timestamp . '&nonce=' . $nonce_str . '&content=' . urlencode($content) . '&signature=' . urlencode($sign);
        return $url;
    }
    /**
     * @xk 执行app支付
     * @method                                 doAppPay
     * @param                                  [type] $pay_order_sn  [description]
     * @param                                  [type] $need_pay  [description]
     * @param                                  [type] $notifyUrl  [description]
     * @return                                 [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                        <zhonghuaxinxing@sina.cn>
     * @City：                                  青岛
     * @Time：2022-02-10Tfalse14:false26:09+080
     */
    public static function doAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl)
    {
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $post_data['merOrderId'] = $pay_order_sn; // 订单支付编号
        $cancel_time = (int)config('web_config.cancel_hour') * 3600;
        $post_data['expireTime'] = date('Y-m-d H:i:s', time() + $cancel_time); // 一小时后自动关闭订单 重新发起
        $post_data['mid'] = config('pay_config.unionpay.mid');
        $post_data['tid'] = config('pay_config.unionpay.tid');
        $post_data['instMid'] = config('pay_config.unionpay.instMid');
        $post_data['tradeType'] = 'APP';
        $post_data['orderDesc'] = '用户使用微信支付商品';
        $post_data['totalAmount'] = strval($need_pay);
        $post_data['notifyUrl'] = $notifyUrl;
        $post_data['returnUrl'] = $returnUrl;
        $post_data['subAppId'] = config('core_config.wechat_app_config.app_id');
        $Authorization = self::getUnionPayAccesstoken($post_data);
        $url = 'https://api-mop.chinaums.com/v1/netpay/wx/app-pre-order'; // 后台下单 正式环境
        $headers = [
            "Content-type: application/json;charset='utf-8'",
            "Authorization:" . $Authorization
        ];
        $result = self::https_request($url, json_encode($post_data), $headers);
        $resultData = json_decode($result, true);
        switch ($resultData['errCode']) {
            case 'SUCCESS':
                $jsApiObj = $resultData['appPayRequest'];
                return $jsApiObj;
                break;
            default:
                throw new \think\Exception($resultData['errMsg'], 404);
                break;
        }
    }
    /**
     * @xk 支付宝支付
     * @method                                      doAliAppPay
     * @param                                       [type] $pay_order_sn  [description]
     * @param                                       [type] $need_pay  [description]
     * @param                                       [type] $notifyUrl  [description]
     * @param                                       [type] $returnUrl  [description]
     * @return                                      [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                             <zhonghuaxinxing@sina.cn>
     * @City：                                       青岛
     * @Time：2022-03-09Tfalse10:false36:false32+080
     */
    public static function doAliAppPay($pay_order_sn, $need_pay, $notifyUrl, $returnUrl)
    {
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $post_data['merOrderId'] = (string)$pay_order_sn; // 订单支付编号
        $cancel_time = (int)config('web_config.cancel_hour') * 3600;
        $post_data['expireTime'] = date('Y-m-d H:i:s', time() + $cancel_time); // 一小时后自动关闭订单 重新发起
        $post_data['mid'] = config('pay_config.unionpay.mid');
        $post_data['tid'] = config('pay_config.unionpay.tid');
        $post_data['instMid'] = config('pay_config.unionpay.instMid');
        $post_data['tradeType'] = 'APP';
        $post_data['orderDesc'] = '用户使用支付宝支付商品';
        $post_data['totalAmount'] = strval($need_pay);
        $post_data['notifyUrl'] = $notifyUrl;
        $post_data['returnUrl'] = $returnUrl;
        $Authorization = self::getUnionPayAccesstoken($post_data);
        $url = 'https://api-mop.chinaums.com/v1/netpay/trade/app-pre-order'; // 后台下单 正式环境
        $headers = [
            "Content-type: application/json;charset='utf-8'",
            "Authorization:" . $Authorization
        ];
        $result = self::https_request($url, json_encode($post_data), $headers);

        // createLog('pay/alipay/log/',$result);
        $resultData = json_decode($result, true);
        switch ($resultData['errCode']) {
            case 'SUCCESS':
                return $resultData['appPayRequest'];
                break;
            default:
                throw new \think\Exception($resultData['errMsg'], 404);
                break;
        }
    }
    /**
     * @xk 执行银联H5支付
     *
     * @Version: V1.0
     * @Author: xkyinzhe <zhonghuaxinxing@sina.cn>
     * @City: 青岛
     * @Time 2024-01-30
     * @param [type] $pay_order_sn
     * @param [type] $need_pay
     * @param [type] $notifyUrl
     * @param [type] $returnUrl
     * @return void
     */
    public static function doUniH5Pay($pay_order_sn = '', $need_pay = 0, $notifyUrl = '', $returnUrl = '')
    {
        // 前台下单模式
        $app_id = config('pay_config.unionpay.app_id');
        $app_key = config('pay_config.unionpay.app_key');
        $timestamp = date('YmdHis');
        $cancel_time = (int)config('web_config.cancel_hour') * 3600;
        $nonce_str = self::nocestr();
        $post_data = [];
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $post_data['merOrderId'] = $pay_order_sn; // 订单支付编号
        $post_data['mid'] = config('pay_config.unionpay.uni_wechat_mid');
        $post_data['tid'] = config('pay_config.unionpay.uni_wechat_tid');
        $post_data['instMid'] = 'H5DEFAULT'; // 银联 云闪付
        $post_data['merAppId'] =  'https://' . $_SERVER['HTTP_HOST'] . '/#/';
        $post_data['expireTime'] = date('Y-m-d H:i:s', time() + $cancel_time); // 一小时后自动关闭订单 重新发起
        $post_data['orderDesc'] = '用户使用云闪付支付订单';
        $post_data['totalAmount'] = strval($need_pay);
        $post_data['notifyUrl'] = $notifyUrl;
        $post_data['returnUrl'] = $returnUrl;
        $content = json_encode($post_data);
        $string = $app_id . $timestamp . $nonce_str . hash('sha256', $content);
        $sign = Base64_Encode(hash_hmac('sha256', $string, $app_key, true));
        $url = 'https://api-mop.chinaums.com/v1/netpay/uac/order'; // 银联测试环境
        $url .= "?authorization=OPEN-FORM-PARAM&appId=" . $app_id . '&timestamp=' . $timestamp . '&nonce=' . $nonce_str . '&content=' . urlencode($content) . '&signature=' . urlencode($sign);
        return $url;
    }
    /**
     * @xk 银联云闪付APP支付
     *
     * @Version: V1.0
     * @Author: xkyinzhe <zhonghuaxinxing@sina.cn>
     * @City: 青岛
     * @Time 2024-01-30
     * @param string $pay_order_sn
     * @param integer $need_pay
     * @param string $notifyUrl
     * @param string $returnUrl
     * @return void
     */
    public static function doUniAppPay($pay_order_sn = '', $need_pay = 0, $notifyUrl = '', $returnUrl = '')
    {
        $cancel_time = (int)config('web_config.cancel_hour') * 3600;
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $post_data['merOrderId'] = $pay_order_sn; // 订单支付编号
        $post_data['expireTime'] = date('Y-m-d H:i:s', time() + $cancel_time); // 一小时后自动关闭订单 重新发起
        $post_data['mid'] = config('pay_config.unionpay.uni_app_mid');
        $post_data['tid'] = config('pay_config.unionpay.uni_app_tid');
        $post_data['instMid'] = 'APPDEFAULT';
        $post_data['limitCreditCard'] = 'false';
        $post_data['orderDesc'] = '用户使用云闪付支付订单';
        $post_data['totalAmount'] = strval($need_pay);
        $post_data['targetAppScheme'] = 'iOS:qmfpppay,xkjpywd;';
        $post_data['notifyUrl'] = $notifyUrl;
        $Authorization = self::getUnionPayAccesstoken($post_data);
        $url = 'https://api-mop.chinaums.com/v1/netpay/uac/app-order'; // 后台下单 正式环境
        $headers = [
            "Content-type: application/json;charset='utf-8'",
            "Authorization:" . $Authorization
        ];
        $result = self::https_request($url, json_encode($post_data), $headers);
        createLog('/pay/log/',json_encode(($post_data)));
        $resultData = json_decode($result, true);
        switch ($resultData['errCode']) {
            case 'SUCCESS':
                $jsApiObj = $resultData['appPayRequest'];
                return $jsApiObj;
                break;
            default:
                throw new \think\Exception($resultData['errMsg'], 404);
                break;
        }
    }
    /**
     * @xk 子订单支付回调
     *
     * @method SubOrderPayBack
     * @Time   2021-10-23
     * @City   青岛
     * @Author xkyinzhe        <zhonghuaxinxing@sina.cn>
     */
    public static function SubOrderPayBack()
    {
        Db::startTrans();
        $param = request()->param();
        $path = 'unionpay/pay/subOrder/';
        $pay_order_sn = $param['merOrderId']; // 发起请求的id
        $content = "===================【" . $pay_order_sn . "】支付回调请求开始==========================\n";
        try {
            if ($param['status'] != 'TRADE_SUCCESS') {
                switch ($param['status']) {
                    case 'NEW_ORDER':
                        throw new \think\Exception("新订单交易", 404);
                        break;
                    case 'UNKNOWN':
                        throw new \think\Exception("交易状态不明确", 404);
                        break;
                    case 'TRADE_CLOSED':
                        throw new \think\Exception("交易关闭", 404);
                        break;
                    case 'WAIT_BUYER_PAY':
                        throw new \think\Exception("等待卖家付款", 404);
                        break;
                    case 'TRADE_REFUND':
                        throw new \think\Exception("订单进入退货流程", 404);
                        break;
                }
            }
            $subOrderModel = new SubOrderModel();
            $orderServices = new OrderServices();
            $financeServices = new FinanceServices();
            $order_info = $subOrderModel->where([['pay_order_sn', '=', $pay_order_sn]])->field('`sub_order_sn`,`user_sn`,`status`,`pay_status`,`shipping_type`,`sub_order_id`')->find();
            if (!$order_info) {
                throw new \think\Exception("订单不存在", 404);
            }
            if ($order_info['pay_status'] != 0) {
                throw new \think\Exception("订单状态错误", 404);
            }
            $order_data = [];
            $shipping_type = $order_info['shipping_type'];
            $order_data['status'] = 1;
            // if ($shipping_type == 2) {
            //     $order_data['status'] = 2; //
            //     $order_data['delivery_time'] = date('Y-m-d H:i:s'); // 自提订单记录发货时间
            // }
            $order_data['pay_status'] = 1;
            $order_data['sub_order_id'] = $order_info['sub_order_id'];
            $order_data['pay_time'] = $param['payTime']; // 支付时间
            $order_data['pay_type'] = 1;
            $order_data['pay_price'] = $param['receiptAmount'] / 100; // 支付金额
            $order_data['pay_code'] = $param['targetOrderId']; // 支付流水号
            $order_res = $subOrderModel->find($order_info['sub_order_id'])->save($order_data);
            $orderServices->syncOrderGoodsStatus($order_info['sub_order_sn']);
            $finance_data = [];
            $finance_data['relation_num'] = $order_info['sub_order_sn'];
            $finance_data['relation_user_num'] = $order_info['user_sn'];
            $finance_data['pay_order_sn'] = $pay_order_sn;
            $finance_data['entry'] = 1;
            $finance_data['money'] = $order_data['pay_price'];
            $finance_data['content'] = '用户购买商品进行支付';
            $finance_data['pay_type'] = 1;
            $finance_data['act'] = 2;
            $financeServices->syncFinance($finance_data);
            echo "SUCCESS";
            $content .= "========================处理成功============================";
            Db::commit();
        } catch (\Exception $e) {
            $content .= "===========================" . $e->getMessage() . "==========================\n";
            Db::rollback();
        };
        createLog($path, $content);
    }
    /**
     * @xk 订单支付回调
     *
     * @method orderPayBack
     * @return [type]       [description]
     * @Time   2021-10-23
     * @City   青岛
     * @Author xkyinzhe     <zhonghuaxinxing@sina.cn>
     */
    public static function orderPayBack()
    {
        Db::startTrans();
        $param = request()->param();
        $path = 'unionpay/pay/order/';
        $pay_order_sn = $param['merOrderId']; // 发起请求的id
        $content = "=============【" . $pay_order_sn . "】支付回调请求开始==========================\n";
        $content .= json_encode($param);
        $suiji = rand(1001, 9000);
        usleep($suiji);
        createLog($path, $content);
        $lock = (new Lock())->lock(['pay_order_sn' => $pay_order_sn], 12000);
        try {
            if (!$lock) {
                throw new \think\Exception("提交过于频繁，请稍后重试", 401);
            }
            if ($param['status'] != 'TRADE_SUCCESS') {
                switch ($param['status']) {
                    case 'NEW_ORDER':
                        throw new \think\Exception("新订单交易", 404);
                        break;
                    case 'UNKNOWN':
                        throw new \think\Exception("交易状态不明确", 404);
                        break;
                    case 'TRADE_CLOSED':
                        throw new \think\Exception("交易关闭", 404);
                        break;
                    case 'WAIT_BUYER_PAY':
                        throw new \think\Exception("等待卖家付款", 404);
                        break;
                    case 'TRADE_REFUND':
                        throw new \think\Exception("订单进入退货流程", 404);
                        break;
                }
            }
            $orderModel = new OrderModel();
            $orderServices = new OrderServices();
            $financeServices = new FinanceServices();
            $taskService = new Task();
            $payModel = new PayModel();
            $pay_data = [];
            $pay_data['pay_code'] = $param['targetOrderId'];
            $pay_data['pay_order_sn'] = $pay_order_sn;
            // 创建机制 保证数据不重复处理
            $payModel->create($pay_data);
            $order_sn = substr($pay_order_sn, 4, 20);
            $order_info = $orderModel
                ->where([['pay_order_sn', '=', $pay_order_sn]])
                ->whereOr([['order_sn', '=', $order_sn]])
                ->field('`order_sn`,`user_sn`,`status`,`pay_status`,`shipping_type`,`order_id`')
                ->find();
            if (!$order_info) {
                throw new \think\Exception("订单不存在", 404);
            }
            if ($order_info['pay_status'] != 0) {
                throw new \think\Exception("订单状态错误", 404);
            }
            echo "SUCCESS";
            $order_data = [];
            $shipping_type = $order_info['shipping_type'];
            $order_data['status'] = 1;
            // if ($shipping_type == 2) {
            //     $order_data['status'] = 2; //
            //     $order_data['delivery_time'] = date('Y-m-d H:i:s'); // 自提订单记录发货时间
            // }
            $targetSys = isset($param['targetSys']) ? $param['targetSys'] : 'WXPay';
            $mid = isset($param['mid']) ? $param['mid'] : '';
            switch ($targetSys) {
                case 'WXPay':
                    $pay_type = 1;
                    break;
                case 'Alipay 2.0':
                    $pay_type = 2;
                    break;
                case 'Alipay 1.0':
                    $pay_type = 2;
                    break;
                case 'UAC':
                    $pay_type = 4;
                    break;
                default:
                    $pay_type = 1;
                    break;
            }
            // $pay_style = 0;
            switch ($mid) {
                case config('pay_config.unionpay.wechat_mid'):
                    $pay_style = 1;
                    break;
                case config('pay_config.unionpay.uni_app_mid'):
                    $pay_style = 2;
                    break;
                case config('pay_config.unionpay.uni_wechat_mid'):
                    $pay_style = 3;
                    break;

                default:
                    $pay_style = 0;
                    break;
            }
            // if ($mid == config('pay_config.unionpay.wechat_mid')) {
            //     $pay_style = 1;
            // }
            $order_data['pay_status'] = 1;
            $order_data['order_id'] = $order_info['order_id'];
            $order_data['pay_time'] = $param['payTime']; // 支付时间
            $order_data['pay_order_sn'] = $pay_order_sn; // 支付编号
            $order_data['pay_type'] = $pay_type;
            $order_data['is_edit_price'] = 1; // 付款成功 不允许再次进行改价
            $order_data['pay_style'] = $pay_style;
            $order_data['pay_price'] = $param['receiptAmount'] / 100; // 支付金额
            $order_data['pay_code'] = $param['targetOrderId']; // 支付流水号
            $order_res = $orderModel->find($order_info['order_id'])->save($order_data);
            // 从这里开始 执行计划任务
            $msgDatax = ['time' => date('YmdHis'), 'msgId' => $order_info['order_sn'], 'jobAction' => 'syncSubOrderPay'];
            // $delay = 5;
            $delay_arr = [3, 4, 5, 6];
            $delay = $delay_arr[array_rand($delay_arr)];
            $taskService->put($msgDatax, $delay);
            // $orderServices->syncSubOrderPay($order_info['order_sn']);
            $finance_data = [];
            $finance_data['relation_num'] = $order_info['order_sn'];
            $finance_data['relation_user_num'] = $order_info['user_sn'];
            $finance_data['entry'] = 1;
            $finance_data['money'] = $order_data['pay_price'];
            $finance_data['pay_order_sn'] = $pay_order_sn;
            $finance_data['content'] = '用户购买商品进行支付';
            $finance_data['pay_type'] = $pay_type;
            $finance_data['act'] = 1;
            $financeServices->syncFinance($finance_data);
            $content .= "========================处理成功============================";

            Db::commit();
            (new Lock())->unlock($lock);
        } catch (\Exception $e) {
            $content .= "===========================" . $e->getMessage() . "==========================\n";
            Db::rollback();
            if ($e->getCode() != 401) {
                (new Lock())->unlock($lock);
            }
        }
        createLog($path, $content);
    }

    /**
     * @xk 执行订单退款操作
     *
     * @method orderRefundPay
     * @return [type]         [description]
     * @Time   2021-11-03
     * @City   青岛
     * @Author xkyinzhe       <zhonghuaxinxing@sina.cn>
     */
    public static function orderRefundPay($data = [])
    {
        $refundOrderModel = new RefundOrderModel();
        $subOrderModel = new SubOrderModel();
        $orderServices = new OrderServices();
        $financeServices = new FinanceServices();
        $post_data = [];
        $post_data['requestTimestamp'] = date('Y-m-d H:i:s');
        $post_data['merOrderId'] = $data['pay_order_sn'];

        switch ((int)$data['pay_style']) {
            case 1:
                $post_data['instMid'] = 'YUEDANDEFAULT';
                $post_data['mid'] = config('pay_config.unionpay.wechat_mid');
                $post_data['tid'] = config('pay_config.unionpay.wechat_tid');
                break;
            case 2:
                $post_data['instMid'] = 'APPDEFAULT';
                $post_data['mid'] = config('pay_config.unionpay.uni_app_mid');
                $post_data['tid'] = config('pay_config.unionpay.uni_app_tid');
                break;
            case 3:
                $post_data['instMid'] = 'H5DEFAULT';
                $post_data['mid'] = config('pay_config.unionpay.uni_wechat_mid');
                $post_data['tid'] = config('pay_config.unionpay.uni_wechat_tid');
                break;

            default:
                $post_data['instMid'] = 'YUEDANDEFAULT';
                $post_data['mid'] = config('pay_config.unionpay.mid');
                $post_data['tid'] = config('pay_config.unionpay.tid');
                break;
        }
        $post_data['refundAmount'] = strval($data['refund_check_price'] * 100);
        $post_data['refundOrderId'] = config('pay_config.unionpay.msgSrcId') . '22' . $data['refund_order_sn'];
        $Authorization = self::getUnionPayAccesstoken($post_data);
        $url = 'https://api-mop.chinaums.com/v1/netpay/refund';
        $headers = [
            "Content-type: application/json;charset='utf-8'",
            "Authorization:" . $Authorization
        ];
        $path = 'unionpay/pay/refund/';
        createLog($path, json_encode($post_data));
        $result = self::https_request($url, json_encode($post_data), $headers);
        createLog($path, $result);
        $result = json_decode($result, true);
        // 判断退款是否成功
        if (!$result) {
            $refund_order_sn = $refundOrderModel->getCodeNo(date('YmdHis'), 20, 1, 'refund_order_sn');
            $refund_order_res = $refundOrderModel->where([['refund_order_sn', '=', $data['refund_order_sn']]])->save(['refund_order_sn' => $refund_order_sn]);
            throw new \think\Exception("退款接口异常，请联系管理员处理", 404);
        }
        if ($result['errCode'] != 'SUCCESS') {
            $refund_order_sn = $refundOrderModel->getCodeNo(date('YmdHis'), 20, 1, 'refund_order_sn');
            $refund_order_res = $refundOrderModel->where([['refund_order_sn', '=', $data['refund_order_sn']]])->save(['refund_order_sn' => $refund_order_sn]);
            throw new \think\Exception('银联返回提示：' . $result['errMsg'], 404);
        }
        if ($result['status'] != 'TRADE_SUCCESS') {
            $refund_order_sn = $refundOrderModel->getCodeNo(date('YmdHis'), 20, 1, 'refund_order_sn');
            $refund_order_res = $refundOrderModel->where([['refund_order_sn', '=', $data['refund_order_sn']]])->save(['refund_order_sn' => $refund_order_sn]);
            throw new \think\Exception("当前交易还未支付完成，请重新发起", 404);
        }
        if ($result['refundStatus'] != 'SUCCESS') {
            $refund_order_sn = $refundOrderModel->getCodeNo(date('YmdHis'), 20, 1, 'refund_order_sn');
            $refund_order_res = $refundOrderModel->where([['refund_order_sn', '=', $data['refund_order_sn']]])->save(['refund_order_sn' => $refund_order_sn]);
            throw new \think\Exception('银联返回提示：' . $result['errMsg'], 404);
        }
        $targetSys = isset($result['targetSys']) ? $result['targetSys'] : 'WXPay';
        switch ($targetSys) {
            case 'WXPay':
                $pay_type = 1;
                break;
            case 'Alipay 2.0':
                $pay_type = 2;
                break;
            case 'Alipay 1.0':
                $pay_type = 2;
                break;
            case 'UAC':
                $pay_type = 4;
                break;
            default:
                $pay_type = 1;
                break;
        }
        // 退款成功 开始写入退款流水
        $finance_data = [];
        $finance_data['relation_num'] = $data['refund_order_sn']; // 售后订单编号
        $finance_data['relation_user_num'] = $data['user_sn'];
        $finance_data['entry'] = 2; // 平台出账
        $finance_data['money'] = $data['refund_check_price'];
        // $finance_data['money'] = $result['totalAmount']/100;
        $finance_data['pay_order_sn'] = $data['pay_order_sn'];
        $finance_data['content'] = '用户进行退款，平台支出';
        $finance_data['pay_type'] = $pay_type;
        $finance_data['act'] = 4; // 申请退款
        $financeServices->syncFinance($finance_data);
        // 开始写入订单状态
        $order_data = [];
        $order_data['refund_price'] = $data['refund_check_price'];
        $order_data['refund_code'] = $result['refundOrderId'];
        $order_data['finish_time'] = date('Y-m-d H:i:s');
        // 开始执行 相关操作
        $order_data['status'] = 1.3; // 退款完成
        if ($data['type'] == 2) {
            $order_data['status'] = 2.5; // 退货完成
        }
        $refund_order_res = $refundOrderModel->where([['refund_order_sn', '=', $data['refund_order_sn']]])->save($order_data);
        // 写入平台流水记录
        $orderServices->syncRefundResult($data['refund_order_sn']);
        return true;
    }
    /**
     * @xk 生成随机字符串
     *
     * @method   nocestr
     * @Version： V2.0
     * @Author   xkyinzhe
     * @Time     2020-10-26T15:26:06+080
     *
     * @return [type] [description]
     */
    public static function nocestr()
    {
        $result = '';
        $str = '1234567890QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
        for ($i = 0; $i < 32; ++$i) {
            $result .= $str[rand(0, 48)];
        }

        return $result;
    }
    /**
     * @xk CURL请求
     *
     * @method https_request
     * @param  [type]        $url                       [description]
     * @param  [type]        $data                      [description]
     * @param  array         $headers                   [description]
     * @return [type]        [description]
     * @Time   2021-10-22
     * @City   青岛
     * @Author xkyinzhe      <zhonghuaxinxing@sina.cn>
     */
    public static function https_request($url, $data = null, $headers = ["Content-type: application/json;charset='utf-8'"])
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        // $error = curl_error($curl);
        // if($error){
        //   throw new \think\Exception($error, 404);
        // }
        curl_close($curl);

        return $output;
    }
    /**
     * @xk 银联请求获取token
     * @method                                      getUnionPayAccesstoken
     * @param                                       [type] $post_data  [description]
     * @return                                      [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                             <zhonghuaxinxing@sina.cn>
     * @City：                                       青岛
     * @Time：2022-02-21Tfalse13:false19:false47+080
     */
    public static function getUnionPayAccesstoken($post_data)
    {
        // Cache::delete('unionpay_access_token');
        $unionpay_access_token = Cache::get('unionpay_access_token');
        if (!$unionpay_access_token || $unionpay_access_token == '') {
            $app_id = config('pay_config.unionpay.app_id');
            $app_key = config('pay_config.unionpay.app_key');
            $timestamp = date('YmdHis');
            $nonce_str = self::nocestr();
            $sign_data = [];
            $sign_data['appId'] = $app_id;
            $sign_data['timestamp'] = $timestamp;
            $sign_data['nonce'] = $nonce_str;
            $sign_data['signMethod'] = 'SHA256';
            $sign_data['signature'] = hash('sha256', $app_id . $timestamp . $nonce_str . $app_key);
            $resultData = self::https_request('https://api-mop.chinaums.com/v1/token/access', json_encode($sign_data));
            $result = json_decode($resultData, true);
            if ($result['errCode'] != '0000') {
                throw new \think\Exception($result['errInfo'], 404);
            }
            $unionpay_access_token = $result['accessToken'];
            Cache::set('unionpay_access_token', $result['accessToken'], 3600);
        }

        return "OPEN-ACCESS-TOKEN AccessToken=" . $unionpay_access_token;
    }
    /**
     * @xk 获取签名字符串
     * @method                                      getSignContent
     * @param                                       [type] $params  [description]
     * @param                                       int $type  [description]
     * @return                                      [type] [description]
     * @Version：V5.0
     * @Author：xkyinzhe                             <zhonghuaxinxing@sina.cn>
     * @City：                                       青岛
     * @Time：2022-03-14Tfalse14:false12:false39+080
     */
    public static function getSignContent($params, $type = 0)
    {
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === self::checkEmpty($v) && "@" != substr($v, 0, 1)) {
                // 转换成目标字符集
                $v = self::characet($v, "utf-8");
                if ($type == 1) {
                    $v = urlencode($v);
                }
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
        unset($k, $v);
        return $stringToBeSigned;
    }
    /**
     * @xk 验证非空
     *
     * @method checkEmpty
     * @param  [type]     $value                     [description]
     * @return [type]     [description]
     * @Time   2021-08-03
     * @City   qingdao
     * @Author xkyinzhe   <zhonghuaxinxing@sina.cn>
     */
    protected static function checkEmpty($value)
    {
        if (!isset($value)) {
            return true;
        }
        if ($value === null) {
            return true;
        }
        if (trim($value) === "") {
            return true;
        }

        return false;
    }
    /**
     * @xk 强行修改字符集
     *
     * @method characet
     * @param  [type]     $data                      [description]
     * @param  [type]     $targetCharset             [description]
     * @return [type]     [description]
     * @Time   2021-08-03
     * @City   qingdao
     * @Author xkyinzhe   <zhonghuaxinxing@sina.cn>
     */
    public static function characet($data, $targetCharset)
    {
        if (!empty($data)) {
            $fileType = "utf-8";
            if (strcasecmp($fileType, $targetCharset) != 0) {
                $data = mb_convert_encoding($data, $targetCharset, $fileType);
            }
        }
        return $data;
    }
}
